package com.riekoff.particlecubeworld.editor;

import java.util.ArrayList;
import java.util.List;

import cc.creativecomputing.CCApp;
import cc.creativecomputing.CCApplicationManager;
import cc.creativecomputing.control.CCControl;
import cc.creativecomputing.events.CCKeyEvent;
import cc.creativecomputing.graphics.CCColor;
import cc.creativecomputing.graphics.export.CCScreenCapture;
import cc.creativecomputing.graphics.shader.CCGLSLShader;
import cc.creativecomputing.graphics.texture.CCTexture.CCTextureTarget;
import cc.creativecomputing.graphics.texture.CCTexture2D;
import cc.creativecomputing.graphics.texture.CCTextureData;
import cc.creativecomputing.graphics.texture.CCTextureIO;
import cc.creativecomputing.io.CCIOUtil;
import cc.creativecomputing.math.CCMath;

import com.riekoff.particlecubeworld.editor.visual.APlaneVisual;
import com.riekoff.particlecubeworld.editor.visual.AVisual;
import com.riekoff.particlecubeworld.editor.zonierung.ADirectEditZonierung;
import com.riekoff.particlecubeworld.editor.zonierung.AZonierungData;
import com.riekoff.particlecubeworld.player.ABoxVisual;

import de.negativrekord.blockworld.BlockWorld;

public class APatternTextureRenderer extends CCApp {
	
	@CCControl(name = "tile raster size", min = 0.001f, max = 1f)
	private float _cTileRasterWidth = 0.1f;
	
	@CCControl(name = "motar thickness", min = 0.0001f, max = 1f)
	private float _cMotarThickness = 0.01f;
	
	@CCControl(name = "motar smooth", min = 0.0001f, max = 1f)
	private float _cMotarSmooth = 0.01f;
	
	@CCControl(name = "motar edge smooth", min = 0.0001f, max = 0.01f)
	private float _cMotarEdgeSmooth = 0.01f;
	
	@CCControl(name = "motar hue", min = 0, max = 1)
	private float motarHue = 0;
	
	@CCControl(name = "motar saturation", min = 0, max = 1)
	private float motarSaturation = 0;
	
	@CCControl(name = "motar brightness", min = 0, max = 1)
	private float motarBrightness = 0;
	
	@CCControl(name = "pattern index 0", min = 0, max = 15)
	private int _cPattern0 = 0;
	
	@CCControl(name = "pattern scale 0", min = 1, max = 10)
	private int _cPatternScale0 = 0;
	
	@CCControl(name = "pattern index 1", min = 0, max = 15)
	private int _cPattern1 = 0;
	
	@CCControl(name = "pattern blend", min = 0, max = 1)
	private float _cPatternBlend = 0;
	
	@CCControl(name = "debug")
	public static boolean _cDebug = false;
	
	@CCControl(name = "save active")
	public static boolean _cSaveActive = false;
	
	public static enum AVisualMode{
		PLANE, BOXES, BLOCK_WORLD
	}

	@CCControl(name = "visual mode")
	private AVisualMode _cVisualMode = AVisualMode.PLANE;
	
	private CCGLSLShader _myShader;
	
	private int[] _myZones = new int[100];
	
	private List<ATilePattern> _myPatterns = new ArrayList<>();
	private ATilePattern _myPattern0 = null;
	private ATilePattern _myPattern1 = null;
	private APatternBlender _cPatternBlender = new APatternBlender();

	private AControllableColorMap _myColorMap0;
	private AControllableColorMap _myColorMap1;
	
	private APatternBlender _cColorBlender = new APatternBlender();
	
	private AZonierungData _myZonierungData;
	private ADirectEditZonierung _myZones0;
	private ADirectEditZonierung _myZones1;
	
	private APatternBlender _cZoneBlender = new APatternBlender();
	
	private CCTexture2D _myRandomTexture;
	
	private AVisual[] _myVisuals;
	private BlockWorld _myBlockWorld;

	@Override
	public void setup() {
		_myVisuals = new AVisual[]{
			new APlaneVisual(this),
			new ABoxVisual(this)
		};
		
		addControls("app", "pattern blender", 0, _cPatternBlender);
		addControls("app", "app", this);
		
		for(String myFile : CCIOUtil.list("pattern", "txt")){
			_myPatterns.add(new ATilePattern("pattern/" + myFile, g));
		}
		if(_cPattern0 < _myPatterns.size())_myPattern0 = _myPatterns.get(_cPattern0);
		if(_cPattern1 < _myPatterns.size())_myPattern1 = _myPatterns.get(_cPattern1);
		
		_myShader = new CCGLSLShader(
			CCIOUtil.classPath(this, "tex_brick_vertex.glsl"),
			CCIOUtil.classPath(this, "tex_brick_fragment.glsl")
		);
		_myShader.load();
		
		_myZonierungData = new AZonierungData(this);
		_myZones0 = new ADirectEditZonierung(_myZonierungData);
		_myZones1 = new ADirectEditZonierung(_myZonierungData);

		addControls("app", "zonierung blender", 1, _cZoneBlender);
		addControls("app", "zone input", 1, _myZonierungData);
		addControls("app", "zonierung 0", 3, _myZones0);
		addControls("app", "zonierung 1", 4, _myZones1);
		
		addControls("app", "farb blender", 2, _cColorBlender);
		
		_myColorMap0 = new AControllableColorMap(CCTextureIO.newTextureData("colorschemekompakt.png"));
		addControls("app", "color map 0", 2, _myColorMap0);
		addControls("farb palette 0", "color map", 0, _myColorMap0.zonesControl());
		
		_myColorMap1 = new AControllableColorMap(CCTextureIO.newTextureData("colorschemekompakt.png"));
		addControls("app", "color map 1", 2, _myColorMap1);
		addControls("farb palette 1", "color map", 0, _myColorMap1.zonesControl());
		
		for(int i = 0; i < _myZones.length;i++){
			_myZones[i] = (int)CCMath.random(5);
		}
		
		CCTextureData myRandom = new CCTextureData(200,200);
		for(int x = 0; x < myRandom.width(); x++ ){
			for(int y = 0; y < myRandom.height(); y++ ){
				myRandom.setPixel(x, y, new CCColor(CCMath.random(),CCMath.random(),CCMath.random()));
			}
		}
		_myRandomTexture = new CCTexture2D(myRandom, CCTextureTarget.TEXTURE_RECT);
	}
	
	private boolean _myDoUpdate = false;

	@Override
	public void update(final float theDeltaTime) {
		_myZonierungData.update(theDeltaTime);
		if(frameCount % 10 == 0){
			_myColorMap0.update(theDeltaTime);
			_myColorMap1.update(theDeltaTime);
			if(_cPattern0 < _myPatterns.size()){
				_myPattern0 = _myPatterns.get(_cPattern0);
				_myZones0.pattern(_myPattern0);
			}
			if(_cPattern1 < _myPatterns.size()){
				_myPattern1 = _myPatterns.get(_cPattern1);
				_myZones1.pattern(_myPattern1);
			}
		}

		_myZones0.update(theDeltaTime);
		_myZones1.update(theDeltaTime);
	}
	
	@Override
	public void keyPressed(CCKeyEvent theKeyEvent) {
		switch(theKeyEvent.keyCode()){
		case VK_Z:
			for(int i = 0; i < _myZones.length;i++){
				_myZones[i] = (int)CCMath.random(5);
			}
			break;
		case VK_C:
			_myColorMap0.randomize(1);
			break;
		case VK_U:
			_myDoUpdate = true;
			break;
		case VK_S:
			CCScreenCapture.capture("export/" + frameCount + ".png", width, height);
			break;
		}
	}
	

	@Override
	public void draw() {
		g.clear();
		
		if(_myPattern0 == null)return;
		if(_myPattern1 == null)return;
		
		g.color(255);
		_myShader.start();
		g.texture(0,_myPattern0.pattern());
		g.texture(1,_myColorMap0.texture());
		g.texture(2, _myZones0.zoneTexture());
		
		g.texture(3,_myPattern1.pattern());
		g.texture(4,_myColorMap1.texture());
		g.texture(5, _myZones1.zoneTexture());
		
		g.texture(7,_myRandomTexture);
		float tileMotarWidth = 1;
		float motarStep = _cMotarThickness;
		
		_myShader.uniform1f("tileMotarWidth", tileMotarWidth);
		_myShader.uniform1f("motarStep", motarStep);
		_myShader.uniform1f("motarSmooth", _cMotarSmooth);
		_myShader.uniform1f("motarEdgeSmooth", _cMotarEdgeSmooth);
		
		_myShader.uniform4f("motarColor", CCColor.createFromHSB(motarHue, motarSaturation, motarBrightness));
		
		_myShader.uniform1i("pattern0", 0);
		_myShader.uniform1i("colorMap0", 1);
		_myShader.uniform1i("zones0", 2);
		_myShader.uniform2f("zone0Dimension",  _myZones0.zoneTexture().width(), _myZones0.zoneTexture().height());
		_myShader.uniform1f("patternScale", _cPatternScale0 * _cTileRasterWidth);
		
		_myShader.uniform1i("pattern1", 3);
		_myShader.uniform1i("colorMap1", 4);
		_myShader.uniform1i("zones1", 5);
		_myShader.uniform2f("zone1Dimension",  _myZones1.zoneTexture().width(), _myZones1.zoneTexture().height());
		_myShader.uniform1i("debug", _cDebug ? 1 : 0);
		

		_myShader.uniform1i("random", 7);
		
		_myShader.uniform1f("colorBlend", _cColorBlender._cBlend);
		_myShader.uniform1f("colorBlendRange", _cColorBlender._cBlendRange);
		_myShader.uniform("colorReverse", _cColorBlender._cReverse);
			
		_myShader.uniform1f("colorXOffset", _cColorBlender._cXOffset);
		_myShader.uniform1f("colorYOffset", _cColorBlender._cYOffset);
		_myShader.uniform1f("colorRandomOffset", _cColorBlender._cRandomOffset);
		
		_myShader.uniform2f("patternDimension0", _myPattern0.width, _myPattern0.height);
		_myShader.uniform2f("patternDimension1", _myPattern1.width, _myPattern1.height);
		_myShader.uniform2f("patternPosition0", 0, 0);
		
		_myShader.uniform1f("patternBlend", _cPatternBlender._cBlend);
		_myShader.uniform1f("patternBlendRange", _cPatternBlender._cBlendRange);
		_myShader.uniform("patternReverse", _cPatternBlender._cReverse);
			
		_myShader.uniform1f("patternXOffset", _cPatternBlender._cXOffset);
		_myShader.uniform1f("patternYOffset", _cPatternBlender._cYOffset);
		_myShader.uniform1f("patternRandomOffset", _cPatternBlender._cRandomOffset);
		

		_myShader.uniform1f("patternZoneScale0", _myZones0.patternScale());
		_myShader.uniform1f("patternZoneScale1", _myZones1.patternScale());
		_myShader.uniform("patternZoneClamp0", _myZones0.clampToPattern());
		_myShader.uniform("patternZoneClamp1", _myZones1.clampToPattern());
		
		_myShader.uniform1f("zoneBlend", _cZoneBlender._cBlend);
		_myShader.uniform1f("zoneBlendRange", _cZoneBlender._cBlendRange);
		_myShader.uniform("zoneReverse", _cZoneBlender._cReverse);
			
		_myShader.uniform1f("zoneXOffset", _cZoneBlender._cXOffset);
		_myShader.uniform1f("zoneYOffset", _cZoneBlender._cYOffset);
		_myShader.uniform1f("zoneRandomOffset", _cZoneBlender._cRandomOffset);
		
		_myVisuals[_cVisualMode.ordinal()].draw(g);
		
		
		g.noTexture();
		_myShader.end();
		
		g.color(255);
//		g.image(_myPattern0.pattern(), 0,0,_myPattern0.width * 30,_myPattern0.height * 10);
		
//		g.noBlend();
//		g.beginShape(CCDrawMode.QUADS);
//		for(int y = 0; y < _myPattern.height; y++){
//			for(int x = 0; x < _myPattern.width; x++){
//				g.color(_myPattern.tileindices[x][y] / 15f);
//				g.vertex(x * _cSpace,y  * _cSpace);
//				g.vertex((x + 1) * _cSpace,y  * _cSpace);
//				g.vertex((x + 1) * _cSpace,(y + 1)  * _cSpace);
//				g.vertex(x * _cSpace,(y + 1)  * _cSpace);
//				
//			}
//		}
//		g.endShape();
	}

	public static void main(String[] args) {
		CCApplicationManager myManager = new CCApplicationManager(APatternTextureRenderer.class);
		myManager.settings().size(1900, 1100);
		myManager.start();
	}
}
